#ifndef __FRAME_BUFFER_OBJECT_H__
#define __FRAME_BUFFER_OBJECT_H__

#pragma once

#include "RenderTextureGLES.h"

namespace Nezha
{
	struct FBOAttachment
	{
		GLuint mZOffset;
		GLuint mNumSamples;

		RenderBufferGLESPtr mRenderBuffer;
		TexturePtr mTexture;

		enum AttachmentType
		{
			AT_NONE = 0,
			AT_RENDER_BUFFER,
			AT_TEXTURE,
		};

		AttachmentType mBufferType;

		FBOAttachment()
			:mZOffset(0), mNumSamples(0), mBufferType(AT_NONE)
		{
			
		}
	};

	//class 

	class FrameBufferObject
	{
	public:
		FrameBufferObject(u16 numSamples);
		~FrameBufferObject();

		bool initializeOnce();

		void bind();

		void swapBuffers();

		bool attachColorBuffer(u16 attachment, FBOAttachment& fboa);

		void detachColorBuffer(u16 attachmenet);

		bool attachDepthBuffer(DepthBufferGLESPtr& db);

		void detachDepthBuffer();
		
		const FBOAttachment& getColorBuffer(u32 index) const
		{
			return mColorBuffers[index];
		}

		FBOAttachment& getColorBuffer(u32 index)
		{
			return mColorBuffers[index];
		}
	private:
		GLsizei mNumSamples;
		GLuint mFBO_GLES;
		GLuint mMultisampleFBO_GLES;

		FBOAttachment mMultisampleColorBuffer;
		DepthBufferGLESPtr mDepthBuffer;
		FBOAttachment mColorBuffers[NEZHA_MAX_MULTIPLE_RENDER_TARGETS];
	};

	class FBORTTManager : public RTTManager
	{
	public:
		FBORTTManager();
		~FBORTTManager();

		struct RenderBufferDesc
		{
			GLenum mFormat;
			u16 mWidth;
			u16 mHeight;
			u16 mNumSamples;

			RenderBufferDesc()
				:mFormat(0), mWidth(0), mHeight(0), mNumSamples(0)
			{
			}
			
			RenderBufferDesc(GLenum format, u16 w, u16 h, u16 numSamples)
				:mFormat(format), mWidth(w), mHeight(h), mNumSamples(numSamples)
			{

			}

			bool operator < (const RenderBufferDesc& rhs) const
			{
				if(mFormat < rhs.mFormat)
				{
					return true;
				}
				else if(mFormat == rhs.mFormat)
				{
					if(mWidth < rhs.mWidth)
					{
						return true;
					}
					else if(mWidth == rhs.mWidth)
					{
						if(mHeight < rhs.mHeight)
						{
							return true;
						}
						else if(mHeight == rhs.mHeight)
						{
							return mNumSamples < rhs.mNumSamples;
						}
					}
				}

				return false;
			}
		};

		virtual void setCurrent(RenderTarget* rt);

		virtual RenderTarget* createRenderTarget(u16 w, u16 h, u16 aa, TexFormat fmt, bool renderTexture = false);

		virtual void destroyRenderTarget(RenderTarget* rt);

		virtual DepthStencilBufferPtr createDepthStencilBuffer(u16 w, u16 h, u16 aa, u8 bit);

		void destroyAll();

		RenderBufferGLESPtr createRenderBuffer(HardwareBuffer::Usage usage, u16 w, u16 h, u16 numSamples, u16 bitDepth = 16);

	protected:
		void _garbageDispose();

	private:
		typedef PMap<RenderBufferDesc, RenderBufferGLESPtr> RenderBufferMap;
		RenderBufferMap mRenderBuffers;

		typedef PArray<RenderTarget*> RenderTargetList;
		RenderTargetList mRenderTargets;

		typedef PArray<DepthStencilBufferPtr> DepthBufferList;
		DepthBufferList mDepthBuffers;
	};
}

#endif //end __FRAME_BUF`FER_OBJECT_H__